﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using YArchitech.ProgressBar;
using HYOpeningCommon.DbOpening;
using HYOpeningCommon.OpeningProfile;
using HYOpeningCommon.Public;
using HYOpeningDesignInput.Public;
using YJKRGeometry;

namespace HYOpeningDesignInput.DbOpeningCreatorFactory
{
	internal abstract class DbWallOpeningCreatorFactory : DbOpeningBaseCreatorFactory
	{
		public DbWallOpeningCreatorFactory(ref List<Document> lstDoc, WindowHandle handle, Dictionary<string, int> dicOpenProfileData) : base(ref lstDoc, handle, dicOpenProfileData)
		{
		}

		public void SetWallOpeningChildObj(DbWallOpeningCreatorFactory wallOpeningCreateFactory)
		{
			this.m_wallOpeningCreateFactory = wallOpeningCreateFactory;
		}

		public new virtual bool CreateDbOpening(MEPData mepData, ref LinkedList<DbOpeningBase> lstDbOpening)
		{
			return this.GetOpeningDataByDuct(mepData.m_lstDuct, mepData.m_lstInfos, ref lstDbOpening) && this.GetOpeningDataByCableTray(mepData.m_lstCableTray, mepData.m_lstInfos, ref lstDbOpening) && this.GetOpeningDataByPipe(mepData.m_lstPipe, mepData.m_lstInfos, ref lstDbOpening);
		}

		private bool GetOpeningDataByDuct(List<Duct> lstDuct, List<HYOpeningDesignInput.Public.PointSort> lstInfos, ref LinkedList<DbOpeningBase> lstDbOpening)
		{
			ProgressBarForm progressBarForm = new ProgressBarForm(lstDuct.Count, ProgressBarStyle.Blocks, true);
			bool result;
			try
			{
				progressBarForm.Text = "风管和墙碰撞检测";
				progressBarForm.ShowInTaskbar = false;
				progressBarForm.Show(this.m_hWndRevit);
				List<Wall> list = new List<Wall>();
				foreach (Duct duct in lstDuct)
				{
					foreach (Autodesk.Revit.DB.Document doc in this.m_lstDoc)
					{
						list.AddRange(Interface.GetAllIntersectSubject<Wall>(duct, doc, BuiltInCategory.OST_Walls));
					}
					if (list.Count == 0)
					{
						progressBarForm.RefreshProgressBar();
					}
					else
					{
						if (!this.TraveAllWall(list, duct, lstInfos, ref lstDbOpening))
						{
							progressBarForm.Dispose();
							return false;
						}
						list.Clear();
						progressBarForm.RefreshProgressBar();
						if (progressBarForm.m_stopTag)
						{
							return false;
						}
					}
				}
				progressBarForm.Dispose();
				result = true;
			}
			catch (Exception ex)
			{
				progressBarForm.Dispose();
				ExceptionLog.WriteLog(ex.Message, true);
				result = false;
			}
			return result;
		}

		private bool GetOpeningDataByCableTray(List<CableTray> lstCableTray, List<HYOpeningDesignInput.Public.PointSort> lstInfos, ref LinkedList<DbOpeningBase> lstDbOpening)
		{
			ProgressBarForm progressBarForm = new ProgressBarForm(lstCableTray.Count, ProgressBarStyle.Blocks, true);
			bool result;
			try
			{
				progressBarForm.Text = "电缆桥架和墙碰撞检测";
				progressBarForm.ShowInTaskbar = false;
				progressBarForm.Show(this.m_hWndRevit);
				List<Wall> list = new List<Wall>();
				foreach (CableTray cableTray in lstCableTray)
				{
					foreach (Autodesk.Revit.DB.Document doc in this.m_lstDoc)
					{
						list.AddRange(Interface.GetAllIntersectSubject<Wall>(cableTray, doc, BuiltInCategory.OST_Walls));
					}
					if (list.Count == 0)
					{
						progressBarForm.RefreshProgressBar();
					}
					else
					{
						if (!this.TraveAllWall(list, cableTray, lstInfos, ref lstDbOpening))
						{
							progressBarForm.Dispose();
							return false;
						}
						list.Clear();
						progressBarForm.RefreshProgressBar();
						if (progressBarForm.m_stopTag)
						{
							return false;
						}
					}
				}
				progressBarForm.Dispose();
				result = true;
			}
			catch (Exception)
			{
				progressBarForm.Dispose();
				result = false;
			}
			return result;
		}

		private bool GetOpeningDataByPipe(List<Pipe> lstPipe, List<HYOpeningDesignInput.Public.PointSort> lstInfos, ref LinkedList<DbOpeningBase> lstDbOpening)
		{
			ProgressBarForm progressBarForm = new ProgressBarForm(lstPipe.Count, ProgressBarStyle.Blocks, true);
			bool result;
			try
			{
				progressBarForm.Text = "水管和墙碰撞检测";
				progressBarForm.ShowInTaskbar = false;
				progressBarForm.Show(this.m_hWndRevit);
				List<Wall> list = new List<Wall>();
				foreach (Pipe pipe in lstPipe)
				{
					foreach (Autodesk.Revit.DB.Document doc in this.m_lstDoc)
					{
						list.AddRange(Interface.GetAllIntersectSubject<Wall>(pipe, doc, BuiltInCategory.OST_Walls));
					}
					if (list.Count == 0)
					{
						progressBarForm.RefreshProgressBar();
						if (progressBarForm.m_stopTag)
						{
							return false;
						}
					}
					else
					{
						if (!this.TraveAllWall(list, pipe, lstInfos, ref lstDbOpening))
						{
							progressBarForm.Dispose();
							return false;
						}
						list.Clear();
						progressBarForm.RefreshProgressBar();
						if (progressBarForm.m_stopTag)
						{
							return false;
						}
					}
				}
				progressBarForm.Dispose();
				result = true;
			}
			catch (Exception)
			{
				progressBarForm.Dispose();
				result = false;
			}
			return result;
		}

		private bool TraveAllWall(List<Wall> lstWall, Element mepCurveElem, List<HYOpeningDesignInput.Public.PointSort> lstInfos, ref LinkedList<DbOpeningBase> lstDbOpening)
		{
			try
			{
				Line mepcurveLine = Interface.GetMEPCurveLine(mepCurveElem);
				if (mepcurveLine == null)
				{
					return false;
				}
				foreach (Wall wall in lstWall)
				{
					if ((int)wall.WallType.Kind != 2 && (int)wall.WallType.Kind != 1)
					{
						foreach (XYZ xyz in Interface.GetCvIntersect2ElemPoints(mepcurveLine, wall))
						{
							if (xyz != null)
							{
								OpeningData openingData = new OpeningData();
								DbOpeningBase dbOpeningBase = null;
								OpeningProfileBase openingProfileBase = null;
								if (mepCurveElem is Duct)
								{
									dbOpeningBase = new DbRectWallOpening();
									if (!Interface.GetOpeningDatas(ref dbOpeningBase, ref openingData, xyz, wall, mepCurveElem, lstInfos))
									{
										continue;
									}
									this.SetStraightOpeningData(ref openingData, 0.0);
									openingProfileBase = new OpeningProfileRect();
									OpeningProfileRect openingProfileRect = openingProfileBase as OpeningProfileRect;
									openingProfileRect.m_cutHeight = openingData.m_cutHeight;
									openingProfileRect.m_cutWidth = openingData.m_cutWidth;
									openingData.m_extendDist = AssistFunc.mmToFeet(Convert.ToDouble(this.m_dicOpeningProfileData["RectOpeningOutSize"]));
									openingData.m_tolerance = AssistFunc.mmToFeet(Convert.ToDouble(this.m_dicOpeningProfileData["CompositeTolerance"]));
									Interface.SetOpeningProfile(ref openingProfileBase, openingData);
									Interface.SetOpeningData2Opening(openingData, ref dbOpeningBase, openingProfileBase);
								}
								else if (mepCurveElem is CableTray)
								{
									dbOpeningBase = new DbRectWallOpening();
									if (!Interface.GetOpeningDatas(ref dbOpeningBase, ref openingData, xyz, wall, mepCurveElem, lstInfos))
									{
										continue;
									}
									this.SetStraightOpeningData(ref openingData, 0.0);
									openingProfileBase = new OpeningProfileRect();
									OpeningProfileRect openingProfileRect2 = openingProfileBase as OpeningProfileRect;
									openingProfileRect2.m_cutHeight = openingData.m_cutHeight;
									openingProfileRect2.m_cutWidth = openingData.m_cutWidth;
									openingData.m_extendDist = AssistFunc.mmToFeet(Convert.ToDouble(this.m_dicOpeningProfileData["RectOpeningOutSize"]));
									openingData.m_tolerance = AssistFunc.mmToFeet(Convert.ToDouble(this.m_dicOpeningProfileData["CompositeTolerance"]));
									Interface.SetOpeningProfile(ref openingProfileBase, openingData);
									Interface.SetOpeningData2Opening(openingData, ref dbOpeningBase, openingProfileBase);
								}
								else if (mepCurveElem is Pipe)
								{
									dbOpeningBase = new DbCircleWallOpening();
									openingProfileBase = new OpeningProfileCircle();
									if (!Interface.GetOpeningDatas(ref dbOpeningBase, ref openingData, xyz, wall, mepCurveElem, lstInfos))
									{
										continue;
									}
									openingData.m_cutWidth = (openingData.m_cutHeight = openingData.m_cutDia);
									this.SetStraightOpeningData(ref openingData, 0.0);
									openingData.m_extendDist = AssistFunc.mmToFeet(Convert.ToDouble(this.m_dicOpeningProfileData["CircleOpeningOutSize"]));
									(openingProfileBase as OpeningProfileCircle).m_dCutDiameter = (openingData.m_cutDia = openingData.m_cutWidth);
									openingData.m_tolerance = AssistFunc.mmToFeet(Convert.ToDouble(this.m_dicOpeningProfileData["CompositeTolerance"]));
									Interface.SetOpeningProfile(ref openingProfileBase, openingData);
									Interface.SetOpeningData2Opening(openingData, ref dbOpeningBase, openingProfileBase);
									DbOpeningBase dbOpeningBase2 = null;
									if (Interface.RefreshOpeningData(dbOpeningBase, this.m_dicOpeningProfileData, ref dbOpeningBase2) && dbOpeningBase2 != null)
									{
										dbOpeningBase = dbOpeningBase2;
									}
								}
								lstDbOpening.AddLast(dbOpeningBase);
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				ExceptionLog.WriteLog(ex.Message, true);
				return false;
			}
			return true;
		}

		private void SetStraightOpeningData(ref OpeningData openingData, double d)
		{
			XYZ directionCutObj = openingData.m_directionCutObj;
			XYZ openingDirection = openingData.m_openingDirection;
			XYZ position = openingData.m_position;
			double num = CommonInterface.GetPipe2WallHAng(directionCutObj, openingDirection, position);
			double num2 = CommonInterface.GetPipe2WallVAng(directionCutObj, openingDirection, position);
			if (Geometry.LessThan(Math.PI*.5, num2))
			{
				num2 = Math.PI - num2;
			}
			if (Geometry.LessThan(Math.PI*.5, num))
			{
				num = Math.PI - num;
			}
			this.m_wallOpeningCreateFactory.SetStraightOpeningData(num, openingData.m_hostWidth, openingData.m_cutWidth, ref openingData.m_cutWidth);
			this.m_wallOpeningCreateFactory.SetStraightOpeningData(num2, openingData.m_hostWidth, openingData.m_cutHeight, ref openingData.m_cutHeight);
			this.m_wallOpeningCreateFactory.SetStraightOpeningData(ref openingData);
		}

		public abstract void SetStraightOpeningData(double dAngle, double dHostWidth, double dCutWidthOrHeight, ref double dOpeningWidthOrHeight);

		public abstract void SetStraightOpeningData(ref OpeningData openingData);

		private DbWallOpeningCreatorFactory m_wallOpeningCreateFactory;
	}
}
